package com.sky.aspect;

import com.sky.anno.TableInject;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Component
@Aspect//通知类
@Slf4j
public class TableInjectAspect {
    //定义切点
    @Pointcut("execution(* com.sky.mapper.*.*(..))&& @annotation(com.sky.anno.TableInject))")
    public void pt() {
    }

    @Before("pt()")
    public void before(JoinPoint joinPoint) {
        log.info("mapper增强--------------------");
        //获取当前方法对象
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        //获取方法上的注解
        TableInject annotation = method.getAnnotation(TableInject.class);
        //判断方法上的参数是否为空
        Object[] params = joinPoint.getArgs();
        if (params == null || params.length == 0) {
            return;
        }
        //方法参数
        //TODO ==结论==主要是给传入的参数对象的属性赋值
        //TODO 进行添加或者修改参数对象为employee或者category,是里面的属性需要自动填充
        Object target = params[0];
        //要填充的值
        LocalDateTime now = LocalDateTime.now();
        Long currentId = BaseContext.getCurrentId();
        try {
            //通过方法的参数对象获取set方法去进行赋值
            //或者通过暴力反射获取
            Method createTimeMethod = target.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
            Method updateTimeMethod = target.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
            Method createUserMethod = target.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
            Method updateUserMethod = target.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
            //获取注解对象的value
            switch (annotation.value()) {
                //对createTime/updateTime/createUser/updateUser进行赋值
                case INSERT:
                    createTimeMethod.invoke(target, now);
                    updateTimeMethod.invoke(target, now);
                    createUserMethod.invoke(target, currentId);
                    updateUserMethod.invoke(target, currentId);
                    break;
                //对updateTime/updateUser进行赋值
                case UPDATE:
                    updateTimeMethod.invoke(target, now);
                    updateUserMethod.invoke(target, currentId);
                    break;
            }
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    //定义切点
    //设置扫描条件,mapper下的方法并且还要有TableInject注解
   /* @Pointcut("execution(* com.sky.mapper.*.* (..))&&@annotation(com.sky.anno.TableInject)")
    public void pt() {
    }

    //前置通知
    @Before("pt()")
    public void before(JoinPoint joinPoint) {
        //获取切点下的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //使用signature的实现类MethodSignature获取方法对象
        Method method = signature.getMethod();
        //获取方法下的注解
        TableInject annotation = method.getAnnotation(TableInject.class);
        //判断方法上的参数
        Object[] args = joinPoint.getArgs();
        //判断参数是否为空
        if (args == null || args.length == 0) {
            return;
        }
        //参数不为空
        Object target = args[0];
        //设置要填充的值
        LocalDateTime now = LocalDateTime.now();
        Long id = BaseContext.getCurrentId();
        try {
            //设置方法参数对象上的set方法
            //target就是参数对象某个实体类
            Method setCreateTime = target.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
            Method setUpdateTime = target.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
            Method setCreateUser = target.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
            Method setUpdateUser = target.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
            //调用方法设置值
            //获取注解上的value
            OperationType value = annotation.value();
            switch (value) {
                case INSERT:
                    setCreateTime.invoke(target, now);
                    setUpdateTime.invoke(target, now);
                    setCreateUser.invoke(target, id);
                    setUpdateUser.invoke(target, id);
                    break;
                case UPDATE:
                    setUpdateTime.invoke(target, now);
                    setCreateTime.invoke(target, id);
                    break;
            }
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }*/
}
